home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / dir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  10.9 KB  |  442 lines

  1. /* Directory routines
  2.    Copyright (C) 1994 Miguel de Icaza.
  3.    
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2 of the License, or
  7.    (at your option) any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. #include <config.h>
  19. #include "tty.h"
  20. #include "fs.h"
  21.  
  22. #include <string.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <errno.h>
  26. #include <sys/stat.h>
  27. #include "mad.h"
  28. #include "global.h"
  29. #define DIR_H_INCLUDE_HANDLE_DIRENT
  30. #include "dir.h"
  31. #include "util.h"
  32. #include "tree.h"
  33. #include "../vfs/vfs.h"
  34.  
  35. /* "$Id: dir.c,v 1.3 1995/09/01 18:57:15 br811563 Exp br811563 $" */
  36.  
  37. /* If true show files starting with a dot */
  38. int show_dot_files = 1;
  39.  
  40. /* If true show files ending in ~ */
  41. int show_backups = 0;
  42.  
  43. /* If false then directories are shown separately from files */
  44. int mix_all_files = 0;
  45.  
  46. /* Reverse flag */
  47. static int reverse = 1;
  48.  
  49. /* Are the files sorted case sensitively? */
  50. static int case_sensitive = 1;
  51.  
  52. #define MY_ISDIR(x) ( (S_ISDIR (x->buf.st_mode) || x->f.link_to_dir) ? 1 : 0)
  53.  
  54. sort_orders_t sort_orders [SORT_TYPES] = {
  55.     { "Unsorted",    unsorted },
  56.     { "Name",        sort_name },
  57.     { "Extension",   sort_ext },
  58.     { "Modify time", sort_time },
  59.     { "Access time", sort_atime },
  60.     { "Change time", sort_ctime },
  61.     { "Size",        sort_size },
  62.     { "Inode",       sort_inode }
  63. };
  64.  
  65. #define string_sortcomp(a,b) case_sensitive ? strcmp (a,b) : strcasecmp (a,b)
  66.  
  67. int unsorted (const file_entry *a, const file_entry *b)
  68. {
  69.     return 0;
  70. }
  71.  
  72. int sort_name (const file_entry *a, const file_entry *b)
  73. {
  74.     int ad = MY_ISDIR (a);
  75.     int bd = MY_ISDIR (b);
  76.     
  77.     if (ad == bd || mix_all_files)
  78.     return string_sortcomp (a->fname, b->fname) * reverse;
  79.     return bd-ad;
  80. }
  81.  
  82. int sort_ext (const file_entry *a, const file_entry *b)
  83. {
  84.     char *exta, *extb;
  85.     int r;
  86.     int ad = MY_ISDIR (a);
  87.     int bd = MY_ISDIR (b);
  88.  
  89.     if (ad == bd || mix_all_files){
  90.     exta = extension (a->fname);
  91.     extb = extension (b->fname);
  92.     r = string_sortcomp (exta, extb);
  93.     if (r)
  94.         return r * reverse;
  95.     else
  96.         return sort_name (a, b);
  97.     } else
  98.     return bd-ad;
  99. }
  100.  
  101. int sort_time (const file_entry *a, const file_entry *b)
  102. {
  103.     int ad = MY_ISDIR (a);
  104.     int bd = MY_ISDIR (b);
  105.  
  106.     if (ad == bd || mix_all_files)
  107.     return (a->buf.st_mtime - b->buf.st_mtime) * reverse;
  108.     else
  109.     return bd-ad;
  110. }
  111.  
  112. int sort_ctime (const file_entry *a, const file_entry *b)
  113. {
  114.     int ad = MY_ISDIR (a);
  115.     int bd = MY_ISDIR (b);
  116.  
  117.     if (ad == bd || mix_all_files)
  118.     return (a->buf.st_ctime - b->buf.st_ctime) * reverse;
  119.     else
  120.     return bd-ad;
  121. }
  122.  
  123. int sort_atime (const file_entry *a, const file_entry *b)
  124. {
  125.     int ad = MY_ISDIR (a);
  126.     int bd = MY_ISDIR (b);
  127.  
  128.     if (ad == bd || mix_all_files)
  129.     return (a->buf.st_atime - b->buf.st_atime) * reverse;
  130.     else
  131.     return bd-ad;
  132. }
  133.  
  134. int sort_inode (const file_entry *a, const file_entry *b)
  135. {
  136.     int ad = MY_ISDIR (a);
  137.     int bd = MY_ISDIR (b);
  138.  
  139.     if (ad == bd || mix_all_files)
  140.     return (a->buf.st_ino - b->buf.st_ino) * reverse;
  141.     else
  142.     return bd-ad;
  143. }
  144.  
  145. int sort_size (const file_entry *a, const file_entry *b)
  146. {
  147.     int ad = MY_ISDIR (a);
  148.     int bd = MY_ISDIR (b);
  149.  
  150.     if (ad == bd || mix_all_files)
  151.     return (b->buf.st_size - a->buf.st_size) * reverse;
  152.     else
  153.     return bd-ad;
  154. }
  155.  
  156. void do_sort (dir_list *list, sortfn *sort, int top, int reverse_f, int case_sensitive_f)
  157. {
  158.     reverse = reverse_f ? -1 : 1;
  159.     case_sensitive = case_sensitive_f;
  160.     qsort (&(list->list) [1], top, sizeof (file_entry), sort);
  161. }
  162.  
  163. void clean_dir (dir_list *list, int count)
  164. {
  165.     int i;
  166.  
  167.     for (i = 0; i < count; i++){
  168.     free (list->list [i].fname);
  169.     list->list [i].fname = 0;
  170.     if (list->list [i].cache != NULL) {
  171.         free (list->list [i].cache);
  172.         list->list [i].cache = NULL;
  173.     }
  174.     }
  175. }
  176.  
  177. /* Used to set up a directory list when there is no access to a directory */
  178. int set_zero_dir (dir_list *list)
  179. {
  180.     char buffer [MC_MAXPATHLEN + MC_MAXPATHLEN];
  181.     char *p, *s;
  182.     int i = 0;
  183.     
  184.     (list->list) [0].fname = strdup ("..");
  185.     (list->list) [0].cache = NULL;
  186.  
  187.     /* FIXME: We need to get the panel definition! to use file_mark */
  188.     (list->list) [0].f.marked = 0;
  189.     mc_get_current_wd (buffer, sizeof (buffer) - 1 );
  190.     if (buffer [strlen (buffer) - 1] == PATH_SEP)
  191.         buffer [strlen (buffer) - 1] = 0;
  192.     for (;;) {
  193.         strcat (buffer, PATH_SEP_STR "..");
  194.         p = vfs_canon (buffer);
  195.         if (mc_stat (p, &((list->list) [0].buf)) != -1){
  196.         free (p);
  197.             break;
  198.     }
  199.         i = 1;
  200.         if ((s = vfs_path (p)) && !strcmp (s, PATH_SEP_STR)){
  201.         free (p);
  202.             return 1;
  203.     }
  204.     strcpy (buffer, p);
  205.     free (p);
  206.     }
  207.     if (i) { /* So there is bogus information on the .. directory's stat */
  208.         (list->list) [0].buf.st_mode &= ~0444;
  209.     }
  210.     return 1;
  211. }
  212.  
  213. /* Return values: -1 = failure, 0 = don't add, 1 = add to the list */
  214. int handle_dirent (dir_list *list, char *filter, struct dirent *dp,
  215.            struct stat *buf1, int next_free, int *link_to_dir,
  216.            int *stalled_link)
  217. {
  218.     if (dp->d_name [0] == '.' && dp->d_name [1] == 0)
  219.     return 0;
  220.     if (!show_dot_files){
  221.     if (dp->d_name [0] == '.'){
  222.         if (!(dp->d_name [1] == 0))
  223.         if (!(dp->d_name [1] == '.' && NLENGTH (dp) == 2))
  224.             return 0;
  225.     }
  226.     }
  227.     if (!show_backups && dp->d_name [NLENGTH (dp)-1] == '~')
  228.     return 0;
  229.     if (mc_lstat (dp->d_name, buf1) == -1)
  230.         return 0;
  231.  
  232.     if (S_ISDIR (buf1->st_mode))
  233.     tree_check (dp->d_name);
  234.     
  235.     /* A link to a file or a directory? */
  236.     *link_to_dir = 0;
  237.     *stalled_link = 0;
  238.     if (S_ISLNK(buf1->st_mode)){
  239.     struct stat buf2;
  240.     if (!mc_stat (dp->d_name, &buf2))
  241.         *link_to_dir = S_ISDIR(buf2.st_mode) != 0;
  242.     else
  243.         *stalled_link = 1;
  244.     }
  245.     if (!(S_ISDIR(buf1->st_mode) || *link_to_dir) && filter &&
  246.     !regexp_match (filter, dp->d_name, match_file))
  247.     return 0;
  248.  
  249.     /* Need to grow the *list? */
  250.     if (next_free == list->size){
  251.     list->list = realloc (list->list, sizeof (file_entry) *
  252.                   (list->size + RESIZE_STEPS));
  253.     if (!list->list)
  254.         return -1;
  255.     list->size += RESIZE_STEPS;
  256.     }
  257.     return 1;
  258. }
  259.  
  260. int do_load_dir(dir_list *list, sortfn *sort, int reverse, int case_sensitive, char *filter)
  261. {
  262.     DIR           *dirp;
  263.     struct dirent *dp;
  264.     int           status, link_to_dir, stalled_link;
  265.     int           next_free = 0;
  266.     struct stat   buf;
  267.  
  268.     start_tree_check (NULL);
  269.     
  270.     dirp = mc_opendir (".");
  271.     if (!dirp){
  272.     return set_zero_dir (list);
  273.     }
  274.     for (dp = mc_readdir (dirp); dp; dp = mc_readdir (dirp)){
  275.     status = handle_dirent (list, filter, dp, &buf, next_free, &link_to_dir,
  276.         &stalled_link);
  277.     if (status == 0)
  278.         continue;
  279.     if (status == -1)
  280.         return next_free;
  281.     list->list [next_free].fnamelen = NLENGTH (dp);
  282.     list->list [next_free].fname = strdup (dp->d_name);
  283.     list->list [next_free].cache = NULL; 
  284.     list->list [next_free].f.marked = 0;
  285.     list->list [next_free].f.link_to_dir = link_to_dir;
  286.     list->list [next_free].f.stalled_link = stalled_link;
  287.     list->list [next_free].buf = buf;
  288.     next_free++;
  289.     if (!(next_free % 32))
  290.         rotate_dash ();
  291.     }
  292.     if (next_free)
  293.     do_sort (list, sort, next_free-1, reverse, case_sensitive);
  294.     else
  295.     return set_zero_dir (list);
  296.     
  297.     mc_closedir (dirp);
  298.     end_tree_check (NULL);
  299.     return next_free;
  300. }
  301.  
  302. int link_isdir (file_entry *file)
  303. {
  304.     struct stat b;
  305.     
  306.     if (S_ISLNK (file->buf.st_mode)){
  307.     mc_stat (file->fname, &b);
  308.     if (S_ISDIR (b.st_mode))
  309.         return 1;
  310.     }
  311.     return 0;
  312. }
  313.  
  314. int if_link_is_exe (file_entry *file)
  315. {
  316.     struct stat b;
  317.  
  318.     if (S_ISLNK (file->buf.st_mode)){
  319.     mc_stat (file->fname, &b);
  320.     return is_exe (b.st_mode);
  321.     }
  322.     return 1;
  323. }
  324.  
  325. static dir_list dir_copy = { 0, 0 };
  326.  
  327. static void alloc_dir_copy (int size)
  328. {
  329.     int i;
  330.         
  331.     if (dir_copy.size < size){
  332.     if (dir_copy.list){
  333.  
  334.         for (i = 0; i < dir_copy.size; i++) {
  335.         if (dir_copy.list [i].fname)
  336.             free (dir_copy.list [i].fname);
  337.         if (dir_copy.list [i].cache)
  338.             free (dir_copy.list [i].cache);
  339.         }
  340.         free (dir_copy.list);
  341.         dir_copy.list = 0;
  342.     }
  343.  
  344.     dir_copy.list = xmalloc (sizeof (file_entry) * size, "alloc_dir_copy");
  345.     for (i = 0; i < size; i++) {
  346.         dir_copy.list [i].fname = 0;
  347.         dir_copy.list [i].cache = NULL;
  348.     }
  349.     dir_copy.size = size;
  350.     }
  351. }
  352.  
  353. /* If filter is null, then it is a match */
  354. int do_reload_dir (dir_list *list, sortfn *sort, int count, int rev,
  355.            int case_sensitive, char *filter)
  356. {
  357.     DIR           *dirp;
  358.     struct dirent *dp;
  359.     int           next_free = 0;
  360.     int           i, found, status, link_to_dir, stalled_link;
  361.     struct stat   buf;
  362.     int          tmp_len;  /* For optimisation */
  363.  
  364.     start_tree_check (NULL);
  365.     dirp = mc_opendir (".");
  366.     if (!dirp)
  367.     return set_zero_dir (list);
  368.  
  369.     alloc_dir_copy (list->size);
  370.     for (i = 0; i < count; i++){
  371.     dir_copy.list [i].fnamelen = list->list [i].fnamelen;
  372.     dir_copy.list [i].fname =    list->list [i].fname;
  373.     dir_copy.list [i].cache =    list->list [i].cache;
  374.     dir_copy.list [i].f.marked = list->list [i].f.marked;
  375.     dir_copy.list [i].f.link_to_dir = list->list [i].f.link_to_dir;
  376.     dir_copy.list [i].f.stalled_link = list->list [i].f.stalled_link;
  377.     }
  378.  
  379.     for (dp = mc_readdir (dirp); dp; dp = mc_readdir (dirp)){
  380.     status = handle_dirent (list, filter, dp, &buf, next_free, &link_to_dir,
  381.         &stalled_link);
  382.     if (status == 0)
  383.         continue;
  384.     if (status == -1)
  385.         return next_free;
  386.     
  387.     tmp_len = NLENGTH (dp);
  388.     for (found = i = 0; i < count; i++)
  389.         if (tmp_len == dir_copy.list [i].fnamelen
  390.         && !strcmp (dp->d_name, dir_copy.list [i].fname)){
  391.         list->list [next_free].f.marked = dir_copy.list [i].f.marked;
  392.         found = 1;
  393.         break;
  394.         }
  395.     
  396.     if (!found)
  397.         list->list [next_free].f.marked = 0;
  398.     
  399.     list->list [next_free].fnamelen = tmp_len;
  400.     list->list [next_free].fname = strdup (dp->d_name);
  401.     list->list [next_free].cache = NULL;
  402.     list->list [next_free].f.link_to_dir = link_to_dir;
  403.     list->list [next_free].f.stalled_link = stalled_link;
  404.     list->list [next_free].buf = buf;
  405.     next_free++;
  406.     if (!(next_free % 16))
  407.         rotate_dash ();
  408.     }
  409.     mc_closedir (dirp);
  410.     end_tree_check (NULL);
  411.     if (next_free)
  412.     do_sort (list, sort, next_free-1, rev, case_sensitive);
  413.     else
  414.     next_free = set_zero_dir (list);
  415.     clean_dir (&dir_copy, count);
  416.     return next_free;
  417. }
  418.  
  419. char *sort_type_to_name (sortfn *sort_fn)
  420. {
  421.     int i;
  422.  
  423.     for (i = 0; i < SORT_TYPES; i++)
  424.     if ((sortfn *) (sort_orders [i].sort_fn) == sort_fn)
  425.         return sort_orders [i].sort_name;
  426.  
  427.     return "Unknown";
  428. }
  429.  
  430. sortfn *sort_name_to_type (char *sname)
  431. {
  432.     int i;
  433.  
  434.     for (i = 0; i < SORT_TYPES; i++)
  435.     if (strcasecmp (sort_orders [i].sort_name, sname) == 0)
  436.         return (sortfn *) sort_orders [i].sort_fn;
  437.  
  438.     /* default case */
  439.     return (sortfn *) sort_name;
  440. }
  441.  
  442.